
#include <stdio.h>
#include <stdint.h>
#include <string.h>

#ifdef _DEBUG
#include "Driver\DrvGPIO.h"
#endif

#include "ir_remo_ctrl.h"
#include "usb_vcom.h"

#include "task_shell.h"																			 
																			 
OS_STK   	task_shell_stk[SHELL_STK_SIZE];	 	/*!< Stack of 'task_init' task.	  */

void task_shell(void * pdata);

OS_TID create_shell(SHELL_CREATE_CONTEXT * context)
{
	OS_TID pid = 0;
	if ( (NULL == context) || (NULL == context->m_get_ch_func)
			|| (NULL == context->m_cmd_tab) )
	{
		return E_INVALID_PARAMETER;
	}
	pid = CoCreateTask(
			task_shell, (void*)(context), SHELL_PRI,
			&task_shell_stk[SHELL_STK_SIZE-1],
			SHELL_STK_SIZE);
	return pid;
}

PCMD_DEF SearchCommand(char * cmd, CMD_DEF * cmd_def)
{
//	PCMD_DEF cmd_def = command_define;

	while ( cmd_def->m_handle )
	{
		if ( strcmp(cmd, cmd_def->m_cmd) ==0 ) return cmd_def;
		cmd_def ++;
	}	
	return NULL;
}

enum _CMD_STATE
{
	CS_STANDBY,
	CS_COMMAND,			// Got command 
	CS_CHANNEL,			// Got channel 
};

typedef enum _CMD_STATE		CMD_STATE;
																			 
void task_shell(void * pdata)
{
// Definations
	SHELL_CREATE_CONTEXT * context = (SHELL_CREATE_CONTEXT *)(pdata);
	GET_CHAR _get_char = context->m_get_ch_func;
	PCMD_DEF cmd_def = NULL;

	CMD_STATE state = CS_STANDBY;
	char ch;
	uint8_t	channel = 0xFF;
	uint8_t	param_count = 0xFF;
	param_t param;

	char 		cmd_str[CMD_LENGTH +1];
	uint8_t		cmd_count = 0;
	uint8_t		error = 0;
	uint8_t		reset = 0;

// Codes
#ifdef _DEBUG
	DrvGPIO_ClrBit(E_GPB, 0);		//<DEBUG> turn on LED
#endif
	
	if ( NULL != context->m_init_func)
	{
		(*context->m_init_func)(IE_INIT);
	}

	while (1)
	{
#ifdef _DEBUG
		DrvGPIO_SetBit(E_GPB, 3);
#endif
		ch = (*_get_char)();
#ifdef _DEBUG
		DrvGPIO_ClrBit(E_GPB, 3);		
#endif
		if ( 0 == ch ) break;
		 
		switch (state)
		{
		case CS_STANDBY:
			cmd_str[cmd_count++] = ch;
			if ( cmd_count >= CMD_LENGTH )
			{
				cmd_str[cmd_count] = 0;
				cmd_count = 0;

				cmd_def = SearchCommand(cmd_str, context->m_cmd_tab);

				if (NULL == cmd_def)   error = 1;
				else
				{
					state = CS_COMMAND;
					param_count = cmd_def->m_param_size;
				}
			}
			break;

		case CS_COMMAND:
			channel = ch - '0';
			if ( channel > 8)	error = 1;
			else
			{
				param = 0;
				state = CS_CHANNEL;
			}
			break;

		case CS_CHANNEL:
			param <<= 4;
			if ( '0' <= ch && ch <= '9' )	param |= ch - '0';
			else if ( 'a' <= ch && ch <= 'f')	param |= ch - 'a' + 0xA;
			else if ( 'A' <= ch && ch <= 'F')	param |= ch - 'A' + 0xA;
			else 
			{
				error = 1;
				break;
			}
			param_count --;
			break;
		}

		if ( error )
		{
			usb_printf("!\r\n");
			error = 0;
			reset = 1;
		}

		if (channel < 8 && 0 == param_count && cmd_def)
		{
			(*cmd_def->m_handle)(channel, param);
			reset = 1;
		}

		if ( reset )
		{
			reset = 0;
			state = CS_STANDBY;	
			param_count = 0xFF;
			channel = 0xFF;
			cmd_def = NULL;
		}
	}
#ifdef _DEBUG
	DrvGPIO_SetBit(E_GPB, 0);	//<DEBUG> turn off LED
#endif

	if ( NULL != context->m_init_func)
	{
		(*context->m_init_func)(IE_EXIT);
	}
	CoExitTask();
}
